/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
 * PARTICULAR PURPOSE.
 * ***************************************************************************/


#include "stdafx.h"
#include <pgl/core/PGLMapZ.h>
#include <pgl/core/PGLMapZPropPage.h>
#include <pgl/core/PGLDataVectors.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif


PGL_IMPLEMENT_DYNCREATE(CPGLMapZ, CPGLMap);

//! Save settings
void CPGLMapZ::SerializeXML(CPGLArchive& ar)
{
	static const TCHAR szTag[] = _T("CPGLMapZ");

	CString data,str;
	markup::CMarkupArchive& xml = *((markup::CMarkupArchive*)ar.GetMarkup());
	if(ar.IsStoring())
	{
		xml.AddChildElem(szTag);
		xml.IntoElem();

			/////////////////////////////////////////////////////////
			// Adding base class
			CPGLMap::SerializeXML(ar);
			
			xml.AddChildElem(_T("ColorMap"),CPGLUtility::ColorMap2String(m_eCMap));

		xml.OutOfElem();
	}
	else
	{
		if  (!xml.FindChildElem(szTag))
				return;

		xml.IntoElem();
			CPGLMap::SerializeXML(ar);

			xml.ResetChildPos();
			if(xml.FindChildElem(_T("ColorMap")))
				m_eCMap=CPGLUtility::String2ColorMap(xml.GetChildData());
			
		xml.OutOfElem();
	}
}


#ifdef _DEBUG
void CPGLMapZ::Dump( CDumpContext& dc ) const
{
    // call base class function first
    CPGLMap::Dump( dc );

    // now do the stuff for our specific class
	dc << _T("CPGLMapZ ID ") << GetID() << "\n";
}
void CPGLMapZ::AssertValid() const
{
    // call inherited AssertValid first
    CPGLMap::AssertValid();
} 
#endif


CPGLMapZ::CPGLMapZ()
: CPGLMap(), m_bDeleteField(false), m_pField(NULL)
{
	m_eCMap=CPGLUtility::ColorMapHsv;
	m_dMin=0;
	m_dMax=1;
	
	LoadBitmap(IDB_PGL_MAPZ_BITMAP);
}

CPGLMapZ& CPGLMapZ::operator = (const CPGLMapZ& l)
{
	// prevent self copy
	if (&l != this)
	{
		// invoke CPGLMap copy assignement operator
		this->CPGLMap::operator=(l);

		m_eCMap=l.m_eCMap;
		m_dMin=l.m_dMin;
		m_dMax=l.m_dMax;

		CleanField();

		m_pField=l.m_pField;
		m_bDeleteField=false;

		LoadBitmap(IDB_PGL_MAPZ_BITMAP);
	}
	return *this;
}

CPGLMapZ::~CPGLMapZ() 
{
	CleanField();
};

void CPGLMapZ::AddContextMenuItems(CMenu* pMenu)
{
	ASSERT_VALID(pMenu);
	// first call base class function
	CPGLMap::AddContextMenuItems(pMenu);

	// add separator
	// add own entries...
}

void CPGLMapZ::AddPropertyPage(CPropertySheet* pPropSheet)
{
	ASSERT_VALID(pPropSheet);
	// call own functions
	CPGLMapZPropPage* propPage=new CPGLMapZPropPage(this);
	pPropSheet->AddPage(propPage);

	// first call base class function
	CPGLMap::AddPropertyPage(pPropSheet);
}

void CPGLMapZ::GetMinMax(double& dMin, double& dMax) const
{
	using namespace contour;
	const TLattice<float>* pLattice=GetLattice();
	if (!m_pField || !pLattice) 
	{
		dMin=0;
		dMax=1;
	}

	double val;
	dMin=std::numeric_limits<double>::infinity();
	dMax=-std::numeric_limits<double>::infinity();

	for (UINT i=0;i<pLattice->GetVertexSize();i++)
	{
		val=m_pField->Eval(pLattice->GetXVertex(i),pLattice->GetYVertex(i));
		dMin=__min(val, dMin);
		dMax=__max(val, dMax);
	}
};

void CPGLMapZ::PlotGfx(gfxinterface::CGfxInterface& gfx)
{
	using namespace contour;

	// first if it is visible
	if (!IsVisible() 
		|| !IsInLayer(gfx.GetLayer())
		|| !m_pField
		|| !GetLattice())
		return;

	UINT i,k;
	double alpha;
	CPGLColor col;

	// calling base class plot
	CPGLMap::PlotGfx(gfx);
	TLattice<float>* pLattice=GetLattice();
	ASSERT(pLattice);

	GFX_ADDCOMMENT(gfx,"--- CPGLMapZ ---");

		
	// updating field limits...
	TLattice<float>::Rect r;
	pLattice->GetBoundingBox(r);
	m_pField->SetLimits( Field::SLimits( r.left, r.right, r.bottom,  r.top) );

	double dMin,dMax;
	GetMinMax(dMin,dMax);

	// generating colors
	CPGLVectorF vColor(3*pLattice->GetVertexSize());
	// sending points by rows
	k=0;
	for (i=0;i<pLattice->GetVertexSize();i++)
	{
		// computing alpha
		alpha=( m_pField->Eval(pLattice->GetXVertex(i), pLattice->GetYVertex(i)) - dMin)/(dMax-dMin);
		// setting color
		CPGLUtility::ColorMap(m_eCMap,alpha,col);
		vColor[3*k]=col.GetRed();
		vColor[3*k+1]=col.GetGreen();
		vColor[3*k+2]=col.GetBlue();

		k++;
	}
	
	DWORD dwFlag=0;

	if (IsWireFrameVisible())
		dwFlag|= gfxinterface::CGfxInterface::SurfWireFrame;

	// stroking
	gfx.DrawSurf(*pLattice, vColor, dwFlag);
}

void CPGLMapZ::SetField(Field* pField, bool bHandleCleaning)
{
	CleanField();

	m_pField=pField;
	m_bDeleteField=bHandleCleaning;
}

void CPGLMapZ::CleanField()
{
	if (m_bDeleteField && m_pField)
	{
		delete m_pField;
		m_pField=NULL;
		m_bDeleteField=false;
	}	
}
